// FolderOut.cpp

#include "StdAfx.h"

#include "Common/FileSystem/FileDir.h"

#include "Common/App/AppRegistry.h"

#include "Agent.h"

#include <vector>


namespace Common
{
namespace Agent
{

static LPCTSTR kTempArcivePrefix = _T("7zA");

void CAgentFolder::GetPathParts(CStringVector &pathParts)
{
  _proxyFolderItem->GetPathParts(pathParts);
}

HRESULT CAgentFolder::CommonUpdateOperation(
    bool deleteOperation,
    bool createFolderOperation,
    bool renameOperation,
    const wchar_t *newItemName,
	const Common::Archive::Update::CActionSet *actionSet,
    const UINT32 *indices, UINT32 numItems,
    IFolderArchiveUpdateCallback *updateCallback100)
{
  Common::Archive::WorkDir::CInfo workDirInfo;
  workDirInfo.Load();
  CString archiveFilePath  = _agentSpec->_archiveFilePath;
  CString workDir = Common::Archive::WorkDir::GetWorkDir(workDirInfo, archiveFilePath);
  FileSystem::CreateComplexDirectory(workDir);

  FileSystem::CTempFile tempFile;
  CString tempFileName;
  if (tempFile.Create(workDir, kTempArcivePrefix, tempFileName) == 0)
    return E_FAIL;

  /*
  if (SetOutProperties(anOutArchive, aCompressionInfo.Method) != S_OK)
    return NFileOperationReturnCode::kError;
  */
  
  ////////////////////////////
  // Save FolderItem;

  CStringVector pathParts;
  GetPathParts(pathParts);

  HRESULT hRes(S_OK);
  if (deleteOperation)
    hRes = _agentSpec->DeleteItems(tempFileName,
        indices, numItems, updateCallback100);
  else if (createFolderOperation)
  {
    hRes = _agentSpec->CreateFolder(tempFileName,
        newItemName, updateCallback100);
  }
  else if (renameOperation)
  {
    hRes = _agentSpec->RenameItem(
        tempFileName,
        indices, numItems,
        newItemName,
        updateCallback100);
  }
  else
  {
    BYTE actionSetByte[ Common::Archive::Update::PairState::kNumValues];
    for (int i = 0; i < Common::Archive::Update::PairState::kNumValues; i++)
      actionSetByte[i] = (BYTE)actionSet->StateActions[i];
    hRes = _agentSpec->DoOperation2(tempFileName, actionSetByte, NULL, updateCallback100);
  }
  
  if(S_OK != hRes)
	return hRes;

  _agentSpec->Close();
  
  // m_FolderItem = NULL;
  
  if (FileSystem::Find::DoesFileExist(archiveFilePath))
    if (!FileSystem::DeleteFileAlways(archiveFilePath))
      return GetLastError();

  tempFile.DisableDeleting();
  if (!Common::FileSystem::MoveFile(tempFileName, archiveFilePath))
    return GetLastError();

  {
    CComPtr<IArchiveOpenCallback> openCallback;
    if (updateCallback100)
    {
      hRes = updateCallback100->QueryInterface(__uuidof(IArchiveOpenCallback), (void **)&openCallback);
	  if(S_OK != hRes)
		return hRes;
    }
    hRes = _agentSpec->ReOpen(openCallback);
	if(S_OK != hRes)
		return hRes;
  }
   
  ////////////////////////////
  // Restore FolderItem;

  CComPtr<IFolderFolder> archiveFolder;
  hRes = _agentSpec->BindToRootFolder(&archiveFolder);
  if(S_OK != hRes)
	return hRes;
  for (size_t i = 0; i < pathParts.size(); i++)
  {
    CComPtr<IFolderFolder> newFolder;
    archiveFolder->BindToFolder(pathParts[i], &newFolder);
    if(!newFolder)
      break;
    archiveFolder = newFolder;
  }

  CComPtr<IArchiveFolderInternal> archiveFolderInternal;
  hRes = archiveFolder.QueryInterface(&archiveFolderInternal);
  if(S_OK != hRes)
	return hRes;
  CAgentFolder *agentFolder;
  hRes = archiveFolderInternal->GetAgentFolder(&agentFolder);
  if(S_OK != hRes)
		return hRes;
  _proxyFolderItem = agentFolder->_proxyFolderItem;
  _proxyArchive = agentFolder->_proxyArchive;
  _parentFolder = agentFolder->_parentFolder;

  return S_OK;
}

STDMETHODIMP CAgentFolder::CopyFrom(
    const wchar_t *fromFolderPath, // test it
    const wchar_t **itemsPaths,
    UINT32 numItems,
    IProgress *progress)
{
  try
  {
	  CComPtr<IFolderArchiveUpdateCallback> updateCallback100;
	  HRESULT hRes(S_OK);
	  if (progress != 0)
	  {
		hRes = progress->QueryInterface(__uuidof(IFolderArchiveUpdateCallback), (void **)&updateCallback100);
		if(S_OK != hRes)
			return hRes;
	  }
	  try
	  {
		hRes = _agentSpec->SetFiles(fromFolderPath, itemsPaths, numItems);
		if(S_OK != hRes)
			return hRes;
		hRes = _agentSpec->SetFolder(this);
		if(S_OK != hRes)
			return hRes;
		return CommonUpdateOperation(false, false, false, NULL,
		  &Common::Archive::Update::kAddActionSet, 0, 0, updateCallback100);
	  }
	  catch(const CString &s)
	  {
		hRes = updateCallback100->UpdateErrorMessage(CString(_T("Error: ")) + s);
		if(S_OK != hRes)
			return hRes;
		return E_FAIL;
	  }
  } catch(...) 
  { return E_OUTOFMEMORY; }
}

STDMETHODIMP CAgentFolder::Delete(const UINT32 *indices, UINT32 numItems, IProgress *progress)
{
  try
  {
	  HRESULT hRes(_agentSpec->SetFolder(this));
	  if(S_OK != hRes)
			return hRes;
	  CComPtr<IFolderArchiveUpdateCallback> updateCallback100;
	  if (progress != 0)
	  {
		CComPtr<IProgress> progressWrapper = progress;
		hRes = progressWrapper->QueryInterface(
			__uuidof(IFolderArchiveUpdateCallback), (void **)&updateCallback100);
		if(S_OK != hRes)
			return hRes;
	  }
	  return CommonUpdateOperation(true, false, false, NULL,
		&Common::Archive::Update::kDeleteActionSet, indices, numItems, updateCallback100);
  } catch(...) 
  { return E_OUTOFMEMORY; }
}

STDMETHODIMP CAgentFolder::CreateFolder(const wchar_t *name, IProgress *progress)
{
  try
  {
	  if (_proxyFolderItem->FindDirSubItemIndex(name) >= 0)
		return ERROR_ALREADY_EXISTS;
	  HRESULT hRes(_agentSpec->SetFolder(this));
	  if(S_OK != hRes)
			return hRes;
	  CComPtr<IFolderArchiveUpdateCallback> updateCallback100;
	  if (progress != 0)
	  {
		CComPtr<IProgress> progressWrapper = progress;
		hRes = progressWrapper->QueryInterface(__uuidof(IFolderArchiveUpdateCallback), (void **)&updateCallback100);
		if(S_OK != hRes)
			return hRes;
	  }
	  return CommonUpdateOperation(false, true, false, name, NULL, NULL, 0, updateCallback100);
  } catch(...) 
  { return E_OUTOFMEMORY; }
}

STDMETHODIMP CAgentFolder::Rename(UINT32 index, const wchar_t *newName, IProgress *progress)
{
  try
  {
	  UINT32 indices []  = {index};
	  //indices.push_back(index);
	  HRESULT hRes(_agentSpec->SetFolder(this));
	  if(S_OK != hRes)
			return hRes;
	  CComPtr<IFolderArchiveUpdateCallback> updateCallback100;
	  if (progress != 0)
	  {
		CComPtr<IProgress> progressWrapper = progress;
		hRes = progressWrapper->QueryInterface(__uuidof(IFolderArchiveUpdateCallback), (void **)&updateCallback100);
		if(S_OK != hRes)
			return hRes;
	  }
	  return CommonUpdateOperation(false, false, true, newName, NULL, indices,
		  1, updateCallback100);
  } catch(...) 
  { return E_OUTOFMEMORY; }
}

STDMETHODIMP CAgentFolder::CreateFile(const wchar_t * /* name */, IProgress * /* progress */)
{
  return E_NOTIMPL;
}

STDMETHODIMP CAgentFolder::SetProperty(UINT32 /* index */, PROPID /* propID */,
    const PROPVARIANT * /* value */, IProgress * /* progress */)
{
  return E_NOTIMPL;
}

}}